package com.tuanzi.loan.business.service.application.impl;

import com.alibaba.fastjson.JSON;
import com.base.common.util.CollectionUtils;
import com.google.common.collect.Lists;
import com.google.gson.JsonObject;
import com.starbaba.model.bean.BadgeInfo;
import com.tuanzi.loan.business.entity.application.*;
import com.tuanzi.loan.business.repository.application.LoanApplicationExportExcludeChannelRepository;
import com.tuanzi.loan.business.repository.application.LoanApplicationExportPlatformRepository;
import com.tuanzi.loan.business.repository.application.LoanApplicationExportProductRepository;
import com.tuanzi.loan.business.repository.application.LoanApplicationExportRepository;
import com.tuanzi.loan.business.service.application.LoanApplicationExportGroupService;
import com.tuanzi.loan.business.service.application.LoanApplicationExportService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.repository.JPAAuditRepository;
import com.tuanzi.loan.core.service.BaseAuditServiceImpl;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.application.LoanApplicationExportRequest;
import com.tuanzi.loan.vo.response.application.LoanApplicationExportResponse;
import com.tuanzi.loan.vo.view.application.Action;
import com.tuanzi.loan.vo.view.application.Badge;
import com.tuanzi.loan.vo.view.application.BoLuoDaiAction;
import com.tuanzi.loan.vo.view.application.ExportReplaceCondition;
import com.tuanzi.loan.vo.view.family.product.LoanApplicationExportView;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Auther: hequnayu
 * @Date: 2019/7/31 14:53
 * @Description:
 */
@Slf4j
@Debug
@Service
@Transactional
public class LoanApplicationExportServiceImpl extends BaseAuditServiceImpl<LoanApplicationExport,Long> implements LoanApplicationExportService {

    @Autowired
    private LoanApplicationExportRepository exportRepository;
    @Autowired
    private LoanApplicationExportGroupService groupService;

    @Autowired
    private LoanApplicationExportPlatformRepository platformRepository;
    @Autowired
    private LoanApplicationExportProductRepository productRepository;
    @Autowired
    private LoanApplicationExportExcludeChannelRepository excludeChannelRepository;
    @Autowired
    private TaskExecutor taskExecutor;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public static final String LOAN_APPLICATION_EXPORTS = "loan-app:exports_%s:type_%s";
    public static final String LOAN_APPLICATION_EXPORTS_DELKEY = "loan-app:exports_%s:*";

    @Override
    public Page<LoanApplicationExportResponse> list(PageSearcher<LoanApplicationExportRequest> pageSearcher) {
        return exportRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
    }

    @Override
    public LoanApplicationExportView loadApplicationExportView(Long id) {
        LoanApplicationExportView view = new LoanApplicationExportView();
        LoanApplicationExport export = exportRepository.findOne(id);
        if (export != null){
            BeanUtils.copyProperties(export, view);
            LoanApplicationExportGroup exportGroup = groupService.findByGroupIdAndType(export.getExportGroupId(), export.getType());
            view.setExportGroupId(exportGroup.getId());
            if (!StringUtils.isEmpty(export.getUserTypes())){
                String userTypes = export.getUserTypes();
                String[] split = userTypes.split(",");
                view.setSelectedUserTypes(Arrays.asList(split));
            }
            if (!StringUtils.isEmpty(export.getDiyLaunchParam())){
                Action action = JSON.parseObject(export.getDiyLaunchParam(), Action.class);
                view.setAction(action);
            }
            if (!StringUtils.isEmpty(export.getBadge())){
                view.setBadge(JSON.parseObject(export.getBadge(), BadgeInfo.class));
            }
            if (!StringUtils.isEmpty(export.getReplaceCondition())){
                view.setExportReplaceCondition(JSON.parseObject(export.getReplaceCondition(), ExportReplaceCondition.class));
            }
            view.setSelectedProducts(productRepository.findAllByExportId(export.getId()).stream().map(p -> p.getProductId().toString()).collect(Collectors.toList()));
            view.setSelectedExcludeChannels(excludeChannelRepository.findAllByExportId(export.getId()).stream().map(c -> c.getChannelId().toString()).collect(Collectors.toList()));
            view.setSelectedPlatforms(platformRepository.findAllByExportId(export.getId()).stream().map(p -> p.getPlatform()).collect(Collectors.toList()));
        }
        return view;
    }

    @Override
    public void cleanExportRedis() {
        taskExecutor.execute(() -> {
            try (Cursor c = stringRedisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match("loan-app:exports_*").count(10000).build())) {
                while (c.hasNext()) {
                    stringRedisTemplate.delete(new String((byte[]) c.next()));
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        });
    }

    @Override
    public void cleanExportRedis(Integer exportGroupId) {
        String cacheKey = String.format(LOAN_APPLICATION_EXPORTS_DELKEY,exportGroupId);
        taskExecutor.execute(() -> {
            try (Cursor c = stringRedisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(cacheKey).count(10000).build())) {
                while (c.hasNext()) {
                    stringRedisTemplate.delete(new String((byte[]) c.next()));
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        });
    }

    @Override
    public void cleanExportRedis(Integer exportGroupId, Integer type) {
        String cacheKey = String.format(LOAN_APPLICATION_EXPORTS,exportGroupId,type);
        taskExecutor.execute(() -> {
            stringRedisTemplate.delete(cacheKey);
        });
    }

    @Override
    public List<LoanApplicationExport> findByGroupId(Integer exportGroupId) {
        return exportRepository.findAllByExportGroupId(exportGroupId);
    }

    @Override
    public LoanApplicationExport saveOrUpdateApplicationExport(LoanApplicationExportView view) {
        LoanApplicationExport exportInfo;
        if (view.getId() != null){
            exportInfo = exportRepository.findOne(view.getId());
            cleanExportRedis(exportInfo.getExportGroupId(),exportInfo.getType()); //删除之前的缓存
        }else{
            exportInfo = new LoanApplicationExport();
        }
        BeanUtils.copyProperties(view, exportInfo);
        exportInfo.setUserTypes(view.getSelectedUserTypes().stream().collect(Collectors.joining(",")));
        LoanApplicationExportGroup exportGroup = groupService.findOne(view.getExportGroupId());
        exportInfo.setType(exportGroup.getType());
        exportInfo.setExportGroupId(exportGroup.getGroupId());
        if (view.getAction() != null){
            Action action = view.getAction();
            action.setLaunch(view.getLaunch());
            action.getLaunchParams().setTitle(view.getTargetTitle());
            action.getLaunchParams().setHtmlUrl(view.getTargeturl());
            exportInfo.setDiyLaunchParam(JSON.toJSONString(action));
        }
        if (view.getBadge() != null){
            exportInfo.setBadge(JSON.toJSONString(view.getBadge()));
        }
        if (view.getExportReplaceCondition() != null){
            exportInfo.setReplaceCondition(JSON.toJSONString(view.getExportReplaceCondition()));
        }

        if (exportInfo.getId() != null){
            platformRepository.deleteByExportId(exportInfo.getId());
            productRepository.deleteByExportId(exportInfo.getId());
            excludeChannelRepository.deleteByExportId(exportInfo.getId());
        }

        saveOrUpdate(exportInfo);

        platformRepository.save(view.getSelectedPlatforms().stream().map(p -> {
            LoanApplicationExportPlatform platform = new LoanApplicationExportPlatform();
            platform.setExportId(exportInfo.getId());
            platform.setPlatform(p);
            return platform;
        }).collect(Collectors.toList()));
        productRepository.save(view.getSelectedProducts().stream().map(p -> NumberUtils.toInt(p)).map(p -> {
            LoanApplicationExportProduct product = new LoanApplicationExportProduct();
            product.setExportId(exportInfo.getId());
            product.setProductId(p);
            return product;
        }).collect(Collectors.toList()));
        excludeChannelRepository.save(view.getSelectedExcludeChannels().stream().map(c -> NumberUtils.toLong(c)).map(c -> {
            LoanApplicationExportExcludeChannel excludeChannel = new LoanApplicationExportExcludeChannel();
            excludeChannel.setExportId(exportInfo.getId());
            excludeChannel.setChannelId(c);
            return excludeChannel;
        }).collect(Collectors.toList()));
        view.setId(exportInfo.getId());
//        cleanExportRedis(exportInfo.getExportGroupId());
        cleanExportRedis();
        return exportInfo;
    }

    @Override
    public void online(LoanApplicationExport export) {
        online(Lists.newArrayList(export));
    }

    @Override
    public void online(List<LoanApplicationExport> exports) {
        if (CollectionUtils.isNotEmpty(exports)){
            exports.stream().forEach(x -> {
                x.setStatus(1);
                saveOrUpdate(x);
                cleanExportRedis();
//                cleanExportRedis(x.getExportGroupId());
            });
        }
    }

    @Override
    public void offline(LoanApplicationExport export) {
        offline(Lists.newArrayList(export));
    }

    @Override
    public void offline(List<LoanApplicationExport> exports) {
        if (CollectionUtils.isNotEmpty(exports)){
            exports.stream().forEach(x -> {
                x.setStatus(0);
                saveOrUpdate(x);
                cleanExportRedis();
//                cleanExportRedis(x.getExportGroupId());
            });
        }
    }

    @Override
    public void delete(LoanApplicationExport export) {
        if (export.getId() != null){
            platformRepository.deleteByExportId(export.getId());
            productRepository.deleteByExportId(export.getId());
            excludeChannelRepository.deleteByExportId(export.getId());
        }
        exportRepository.delete(export);
        cleanExportRedis();
//        cleanExportRedis(export.getExportGroupId());
    }

    @Override
    protected JPAAuditRepository<LoanApplicationExport, Long> getRepository() {
        return exportRepository;
    }
}
